home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr42 / vat041.zip / SOUND.C < prev    next >
C/C++ Source or Header  |  1995-03-19  |  68KB  |  2,144 lines

  1. /**************************************************************************
  2.                         VARMINT'S AUDIO TOOLS
  3.  
  4.   Source code: SOUND.C
  5.                Turbo C++ V 3.1
  6.  
  7.                Be careful about the memory model!  The definition for
  8.                SAMPLE will define what model you should use.
  9.  
  10.   Written by: Peter Sprenger and
  11.  
  12.               Eric Jorgensen (Feb, 1995)
  13.               smeagol@rt66.com
  14.  
  15.  
  16.   sound.c is an adaptation (by Eric Jorgensen) from Peter Sprenger's
  17.   SoundX library.  Eric's modifications (In part) are as follows:
  18.  
  19.     - Removal of all VOC, PLAY, and MIXER functions
  20.     - reprogramming of DMA functions
  21.     - Addition of MIDI functions
  22.     - Addition of an interrupt driven sound handler
  23.     - Addition of numerous comments (about 98% of all comments are Eric's)
  24.     - Consolidation of all functions into a single file
  25.     - Rewriting of some of Peter's original functions to improve
  26.       readability and performance.
  27.  
  28. ----------------------------------------------------------------------
  29.  Peter Sprenger's Original Copywrite is as follows:
  30.  
  31.  
  32.  * Copyright 1993 by Peter Sprenger   Pete@amber.dinoco.de
  33.  *                   5014 Kerpen 3
  34.  *                   Germany
  35.  *
  36.  * Permission to use, copy, modify, and distribute this
  37.  * software and its documentation for any purpose and without
  38.  * fee is hereby granted, provided that the above copyright
  39.  * notice appear in all copies.  The author Peter Sprenger
  40.  * makes no representations about the suitability of this
  41.  * software for any purpose.  It is provided "as is" without
  42.  * express or implied warranty.
  43. ----------------------------------------------------------------------
  44.  
  45.  In the spirit of Peter's effort, I am offering my modification of his
  46.  library as FREEWARE.  You are free to use it and distribute this
  47.  library, but you may charge no fee for it.  If you construct another
  48.  sound library based on this one, it must be freeware, too.  This
  49.  restriction does not apply to programs that only use this library to
  50.  generate audio output.  (ie:  if you make a game that uses this
  51.  library for sound generation, you can charge all the money
  52.  you want for your game.)
  53.  
  54.                            **** WARNING ****
  55.  
  56.  Use Varmint's Audio tools at your own risk.  This code has not undergone
  57.  any sort of rigourous testing and has been found to cause cancer in
  58.  laboratory rats.
  59.  
  60. **************************************************************************/
  61.  
  62.  
  63.  
  64. #include "sound.h"
  65.  
  66. #define CINTNO 0
  67. #define SLAVEPIC 2
  68. #define RTCINTNO 8
  69. #define WORD unsigned int
  70. #define BYTE unsigned char
  71. #define TD midi_data->track[i] + trkloc[i]
  72.  
  73. static cardtype CheckHard(void);
  74. static int test_int(void);
  75. static int scan_int(void);
  76. static int FM_Detect(void);
  77. BYTE FM_Status(void);
  78. int DSP_Reset(void);
  79. BYTE DSP_Read(void);
  80. void DSP_Write(BYTE output);
  81. WORD DSP_GetVersion(void);
  82. void SB_SetVect(void);
  83. void SB_RemoveVect(void);
  84. int get_sb_env(void);
  85. int CardCheck(void);
  86. cardtype WhichCard(void);
  87. BYTE int2vect(BYTE intnr);
  88. void enable_int(BYTE nr);
  89. void disable_int(BYTE nr);
  90. void InitT2(void);
  91. void measure(void);
  92. void dma_set(BYTE far *sound_address,WORD len,BYTE channel);
  93. WORD polldma(BYTE channel);
  94. int ReadVarLen(BYTE *data,long int *value);
  95. long int ReadLong(FILE *infile);
  96. int ReadShort(FILE *infile);
  97. void MidiPlayer(void);
  98. int getvoice(VOICE v[],int track,int channel, int note);
  99.  
  100. static void far interrupt (*orgint)(void) = NULL;
  101. static void far interrupt (*orgtick)(void)= NULL;
  102. static void far interrupt (*orgirqint)(void) = NULL;
  103. static void far (*call_func)(void);
  104.  
  105.  
  106. static WORD ioaddr[6]={0x220,0x240,0x210,0x230,0x250,0x260};
  107. static WORD FM_off[9]={0,0x100,0x200,0x800,0x900,0xa00,0x1000,0x1100,0x1200};
  108. static BYTE FM_fnr[12]={0x57,0x6b,0x81,0x98,0xb0,0xca,0xe5,0x02,0x20,0x41,0x63,0x87};
  109. static BYTE FM_key_or[12]={1,1,1,1,1,1,1,2,2,2,2,2};
  110. static BYTE intrx[5]={7,5,2,3,10};
  111.  
  112. static BYTE FM_key[9],FM_keyscale1[9],FM_keyscale2[9];
  113. static BYTE FM_vol[9] = {0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f};
  114.  
  115.  
  116.  
  117. WORD io_addr,intnr,dma_ch,card_id,fm_addr,fm_left,fm_right,fm_both;
  118. static WORD mue3,mue23,dsp_vers,wh_card,rythm=0xbd00;
  119.  
  120. volatile BYTE voc_mode,tst_cnt,dma_sb_busy;
  121.  
  122. static WORD dma_adr[8]= {0x00,0x02,0x04,0x06,0xc0,0xc4,0xc8,0xcc};
  123. static WORD dma_len[8]= {0x01,0x03,0x05,0x07,0xc2,0xc6,0xca,0xce};
  124. static WORD dma_page[8]={0x87,0x83,0x81,0x82,0x8f,0x8b,0x89,0x8a};
  125. WORD dma_bufferlen = 60;
  126. WORD dma_bytesahead =100;
  127. BYTE far *dma_buffer = NULL;
  128. SBERROR sberr = 0;
  129. char *errname[] = {
  130.   "Cannot detect FMchip",
  131.   "Cannot detect DSP",
  132.   "Cannot find an open IRQ",
  133.   "Cannot find an open DMA channel",
  134.   "Cannot allocate memory for DMA buffer"};
  135.  
  136. static WORD timer_val,timer_hold,timer_diff,mue999;
  137. static WORD timadd,timsum;
  138. MIDI *midi_data = NULL;
  139. int midi_reset = TRUE;
  140. int midi_on = FALSE;
  141. float midi_callfreq = 1.0;
  142. float midi_usertempo = 2.0;
  143. float midi_tempoadjust = 2.0;
  144. BYTE music_volume = 0x32;
  145. DWORD vclock=0;
  146. int debugnum=0;
  147. WORD DSP_overhead = 0;
  148. int sounds_in_queue = 0;
  149. int sample_rate = 11000;
  150. float interrupt_time_period;
  151.  
  152. SAMPLE *sounddata[MAXSOUNDS];
  153. DWORD soundpos[MAXSOUNDS];
  154.  
  155.  
  156. extern unsigned _stklen = 8000;   // The stack is usually only 4K, but
  157.                                   // I was getting stack overflow problems
  158.                                   // with that ammount.
  159.  
  160.  
  161.  
  162.  
  163.  
  164.  
  165. /**************************************************************************
  166.   void Go_Varmint(void)
  167.   void Dropdead_Varmint(void)
  168.  
  169.   DESCRIPTION:  Starts/stops the interrupt routine for Varmint's audio tools
  170.  
  171. **************************************************************************/
  172. void Go_Varmint(void)
  173. {
  174.   SB_SetVect();                         // Install the looper
  175.   DSP_Write(0x48);                       // Set DSP for 8bit DMA
  176.   DSP_Write((dma_bufferlen) & 0xff);  // Write length low byte
  177.   DSP_Write((dma_bufferlen) >> 8);    // Write length high byte
  178.  
  179.   dma_set(dma_buffer,dma_bufferlen,dma_ch);
  180.   DSP_Write(0x1C);                       // Set DSP for Autoinit 8bit DMA
  181.  
  182.  
  183.   DSP_Write(DSP_INVOKE_INTR);           // Ignition!
  184. }
  185.  
  186. void Dropdead_Varmint(void)
  187. {
  188.   DSP_Write(0xD0);                      // Halt DMA
  189.   SB_RemoveVect();
  190. }
  191. /*  ---------------  FM  Stuff ------------ */
  192.  
  193.  
  194.  
  195. /**************************************************************************
  196.   void FM_Write(WORD data)
  197.  
  198.   DESCRIPTION: Writes a byte to the FM chip.  The high byte is the
  199.                register, the low byte is the data.
  200.  
  201. **************************************************************************/
  202. void FM_Write(WORD data)
  203. {
  204.   asm mov dx,fm_addr;             // FM ddress
  205.   asm mov ax,data;                // register and data into accumulator
  206.  
  207.   asm xchg al,ah;                 //  exchange accumulator bytes
  208.   asm out dx,al;                  //  write register address to FM chip
  209.  
  210.   asm mov cx,mue3;                // Wait 3 micro seconds
  211. loop1:
  212.   asm loop loop1;
  213.  
  214.   asm inc dx;                     // inc FM address to data write port
  215.   asm mov al,ah;                  // put the data into the low byte of AX
  216.   asm out dx,al;                  // write data to the FM chip
  217.  
  218.   mdelay(mue23);                  // wait 23 microseconds
  219. }
  220.  
  221.  
  222. /**************************************************************************
  223.   void FM_Reset()
  224.  
  225.   DESCRIPTION:  Resets the FM chip by clearing all the registers then
  226.                 setting a few appropriate bits.
  227.  
  228. **************************************************************************/
  229. void FM_Reset(void)
  230. {
  231.   WORD i;
  232.   for(i = 0; i <= 0xf500 ; i+= 0x100) FM_Write(i);
  233.   FM_Write(0x0120);                 // Turn on Wave form control
  234.   FM_Write(0xbdc0);                 // Set AM and Vibrato to high
  235. }
  236.  
  237.  
  238. /**************************************************************************
  239.   BYTE FM_Status()
  240.  
  241.   DESCRIPTION:  Reads the status byte of the FM chip
  242.  
  243. **************************************************************************/
  244. BYTE FM_Status(void)
  245. {
  246.   asm mov dx,fm_addr;
  247.   asm in al,dx;
  248.   return(_AL);
  249. }
  250.  
  251.  
  252. /**************************************************************************
  253.   static int FM_Detect()
  254.  
  255.   DESCRIPTION:  Detects the presence of an FM chip
  256.  
  257. **************************************************************************/
  258. static int FM_Detect(void)
  259. {
  260.   FM_Write(0x0100); /* init Test register */
  261.  
  262.   FM_Write(0x0460); /* reset both timer */
  263.   FM_Write(0x0480); /* enable interrupts */
  264.   if(FM_Status() & 0xe0) return(FALSE);
  265.  
  266.   FM_Write(0x02ff); /* write ffh to timer 1 */
  267.   FM_Write(0x0421); /* start timer 1 */
  268.   if(fm_addr==0x388) msdelay(21); /* wait 21000 mcs */
  269.   else mdelay(mcalc(80));   /* wait at least 80 microsec */
  270.   if((FM_Status() & 0xe0)!=0xc0) return(FALSE);
  271.  
  272.   FM_Write(0x0460); /* reset both timer */
  273.   FM_Write(0x0480); /* enable interrupts */
  274.   return(TRUE);
  275. }
  276.  
  277.  
  278.  
  279. /**************************************************************************
  280.   void FM_SetVoice(BYTE voice,BYTE *ins)
  281.  
  282.   DESCRIPTION: Sets the voice from an 11 byte array
  283.  
  284.     BYTE    ID
  285.  
  286.       0      Ampmod /vib /envtype /scale rate/ mod freq mult (oper 1)
  287.       1      Ampmod /vib /envtype /scale rate/ mod freq mult (oper 2)
  288.       2      Key level scaling/ total level (oper 1)
  289.       3      Key level scaling/ total level (oper 2)
  290.       4      Attack Rate/ Decay rate  (oper 1)
  291.       5      Attack Rate/ Decay rate  (oper 2)
  292.       6      Sustain Level/ Release rate (oper 1)
  293.       7      Sustain Level/ Release rate (oper 2)
  294.       8     Feedback / Algorythm (oper 1&2)
  295.       9      Wave Form  Select (oper 1)
  296.       10    Wave Form  Select (oper 2)
  297.  
  298. **************************************************************************/
  299. void FM_SetVoice(BYTE voice,BYTE *ins)
  300. {
  301.   if(voice > 8) return;
  302.  
  303.   FM_keyscale1[voice]=ins[2] & 0xc0;            // store key scaling for FM_Vol
  304.   FM_keyscale2[voice]=ins[3] & 0xc0;
  305.                                             // Write voice data
  306.   FM_Write((0x2000 + FM_off[voice]) | ins[0]);
  307.   FM_Write((0x2300 + FM_off[voice]) | ins[1]);
  308.                                             // For the next tow, we want to
  309.                                             // make sure current volume is
  310.                                             // preserved.
  311.   FM_Write((0x4000 + FM_off[voice]) | (ins[2] & 0xc0) | FM_vol[voice]);
  312.   FM_Write((0x4300 + FM_off[voice]) | (ins[3] & 0xc0) | FM_vol[voice]);
  313.   FM_Write((0x6000 + FM_off[voice]) | ins[4]);
  314.   FM_Write((0x6300 + FM_off[voice]) | ins[5]);
  315.   FM_Write((0x8000 + FM_off[voice]) | ins[6]);
  316.   FM_Write((0x8300 + FM_off[voice]) | ins[7]);
  317.   FM_Write((0xc000 + voice * 0x100) | ins[8]);
  318.   FM_Write((0xE000 + FM_off[voice]) | ins[9]);
  319.   FM_Write((0xE300 + FM_off[voice]) | ins[10]);
  320. }
  321.  
  322.  
  323. /**************************************************************************
  324.   void FM_SetFreq(BYTE voice,int freq)
  325.  
  326.   DESCRIPTION: sets an explicit pseudo frequency (0 - 0xffff)
  327.  
  328.   Note: There is no way to really set a direct frequency on an FM
  329.         chip, so I wrote this routine which is based on octaves, so I
  330.         imagine it is slightyl non-linear.  Still, it is good for
  331.         special effects.
  332.  
  333. **************************************************************************/
  334. void FM_SetFreq(BYTE voice,WORD freq)
  335. {
  336.   BYTE highbits,lowbits;
  337.   WORD data,frac;
  338.   int octave;
  339.  
  340.   octave = (freq / 0x2000);       // Extract octtave number (0-7)
  341.                                   // convert remaining fraction into a
  342.                                   // 10 bit value.
  343.   frac = ((double)(freq - octave * 0x2000)/(double)0x2000) * 0x157 + 0x157;
  344.  
  345.   highbits = (frac & 0x300) >> 8; // divide fraction into low and high bits
  346.   lowbits = frac & 0xff;
  347.  
  348.   data=0xa000+(voice<<8)|lowbits; // store low bits for now
  349.   FM_key[voice]=highbits|(octave<<2);  // save high bits for Key_on(); (octave 4)
  350.   FM_Write(data);                 // write low bits to FM chip;
  351. }
  352.  
  353. /**************************************************************************
  354.   void FM_SetNote(BYTE voice,BYTE note)
  355.  
  356.   DESCRIPTION: sets the frequency for a chromatic note
  357.  
  358. **************************************************************************/
  359. void FM_SetNote(BYTE voice,BYTE note)
  360. {
  361.   BYTE blk,notex;
  362.   WORD data;
  363.                               //  calculate freq number and octave
  364.   notex=note-24;
  365.   blk=1;
  366.   while(notex>=12)
  367.   {
  368.     notex-=12;
  369.     blk++;                    // octave number
  370.   }
  371.   data=0xa000+(voice<<8)|FM_fnr[notex];
  372.   FM_key[voice]=FM_key_or[notex]|(blk<<2); // save part of the note for Key_on()
  373.   FM_Write(data);             // write note to the chip
  374. }
  375.  
  376.  
  377. /**************************************************************************
  378.   void FM_SetVol(BYTE voice,BYTE vol)
  379.  
  380.   DESCRIPTION: The the volume (0-63) for a voice.
  381.  
  382. **************************************************************************/
  383. void FM_SetVol(BYTE voice,BYTE vol)
  384. {
  385.   if (voice >8) return;
  386.  
  387.   FM_vol[voice] = (0x3f - (vol & 0x3f));
  388.  
  389.   FM_Write((0x4000+FM_off[voice]) |FM_vol[voice] | FM_keyscale1[voice]);
  390.   FM_Write((0x4300+FM_off[voice]) |FM_vol[voice] | FM_keyscale2[voice]);
  391.  
  392. }
  393.  
  394. /*  A NOTE ABOUT RYTHM FUNCTIONS:
  395.  
  396.   I've only played around with these functions a little bit. Here are some
  397.   things that I've learned:
  398.  
  399.     - only channels 6,7,and 8 are affected by the rythm mode.
  400.     - You will need to develop special instrument definitions to get
  401.       the rythm instruments to sound right.  The most important parameters
  402.       in a rythm instrument definition are attack/decay/sustain rates and
  403.       the waveform (bytes 9 and 10).
  404.     - channels 6,7, and 8 each behave differently in rythm mode:
  405.  
  406.         6 - Instrumental.  Sounds like a triangle
  407.         7 - White noise.  Sounds like a snare drum
  408.         8 - High white noise.  Sounds like a Cymbal.
  409.  
  410.     - If you want to add white noise effects to your program (Gun shots
  411.       engines, etc...)  channel 7 in rythm  mode is a good source.
  412.  
  413.                                       - ERIC
  414. */
  415.  
  416.  
  417.  
  418. /**************************************************************************
  419.   void FM_RythmMode(BYTE bool)
  420.  
  421.   DESCRIPTION:  Turns on/off rythm mode based on input.
  422.  
  423. **************************************************************************/
  424. void FM_RythmMode(BYTE bool)
  425. {
  426.   WORD data;
  427.  
  428.   if(bool) data=0xbde0;
  429.   else data=0xbdc0;
  430.   rythm=data;
  431.   FM_Write(data);
  432. }
  433.  
  434.  
  435. /**************************************************************************
  436.   void FM_RythmOn(BYTE inst)
  437.  
  438.   DESCRIPTION: Turns on a Specified  rythm instrument. You should use these
  439.                 definitions:
  440.  
  441.                       FM_HIHAT
  442.                       FM_TOPCYM
  443.                       FM_TOMTOM
  444.                       FM_SNARE
  445.                       FM_BASS
  446.  
  447. **************************************************************************/
  448. void FM_RythmOn(BYTE inst)
  449. {
  450.   rythm|=inst;
  451.   FM_Write(rythm);
  452. }
  453.  
  454. /**************************************************************************
  455.   void FM_RythmOff(BYTE inst)
  456.  
  457.   DESCRIPTION: Turns off a Specified  rythm instrument. You should use these
  458.                 definitions:
  459.  
  460.                       FM_HIHAT
  461.                       FM_TOPCYM
  462.                       FM_TOMTOM
  463.                       FM_SNARE
  464.                       FM_BASS
  465.  
  466. **************************************************************************/
  467. void FM_RythmOff(BYTE inst)
  468. {
  469.   rythm&=(~inst);
  470.   FM_Write(rythm);
  471. }
  472.  
  473.  
  474. /**************************************************************************
  475.   void FM_KeyOn(BYTE voice)
  476.  
  477.   DESCRIPTION: Turn on an FM voice.  (actually it initiates  it.)
  478.  
  479. **************************************************************************/
  480. void FM_KeyOn(BYTE voice)
  481. {
  482.   WORD data;
  483.  
  484.   if(voice > 8) return;
  485.  
  486.   data=0xb000+(voice<<8);            // set write address
  487.   data |= FM_key[voice]|0x20;        // set key on bit and frequency
  488.    FM_Write(data);
  489. }
  490.  
  491.  
  492. /**************************************************************************
  493.   void FM_KeyOff(BYTE voice)
  494.  
  495.   DESCRIPTION: Turn off an FM voice
  496.  
  497. **************************************************************************/
  498. void FM_KeyOff(BYTE voice)
  499. {
  500.   WORD data;
  501.  
  502.   if(voice > 8) return;
  503.  
  504.   data=0xb000+(voice<<8);            // set address
  505.   data |= FM_key[voice];              // preserve frequency data
  506.   FM_Write(data);
  507.                                      //  working.
  508. }
  509.  
  510.  
  511.  
  512. /*  ---------------  DSP  Stuff ------------ */
  513.  
  514.  
  515.  
  516.  
  517. /**************************************************************************
  518.   int DSP_Reset()
  519.  
  520.   DESCRIPTION: Resets the DSP
  521.  
  522. **************************************************************************/
  523. int DSP_Reset(void)
  524. {
  525.   int i;
  526.  
  527.   asm mov dx,io_addr;                   // load address for dsp reset
  528.   asm add dx,DSP_RESET;
  529.   asm mov al,1
  530.   asm out dx,al;                        // Send a 1 to the DSP
  531.  
  532.   mdelay(mcalc(mue3));                  // Wait three micro seconds
  533.  
  534.   asm mov dx,io_addr;                   // load address again
  535.   asm add dx,DSP_RESET;
  536.   asm mov al,0
  537.   asm out dx,al;                        // send a 0 to the DSP
  538.  
  539.   for(i=0;i<50;i++)                     // DSP should send back an 0xaa
  540.   {
  541.     mdelay(mcalc(mue3));
  542.     if(DSP_Read()==0xaa) return(TRUE);
  543.   }
  544.  
  545.   return(FALSE);
  546. }
  547.  
  548.  
  549. /**************************************************************************
  550.   BYTE DSP_Read()
  551.  
  552.   DESCRIPTION:  reads a byte from the dsp
  553.  
  554.  
  555. **************************************************************************/
  556. BYTE DSP_Read(void)
  557. {
  558.   asm mov dx,io_addr;               // load address to read status byte
  559.   asm add dx,DSP_RSTATUS;
  560. loop:
  561.   asm in al,dx;                     // read until high bit is set
  562.   asm test al,0x80;
  563.   asm jz loop
  564.  
  565.   asm mov dx,io_addr;               // read byte from output address
  566.   asm add dx,DSP_READ;
  567.   asm in al,dx;
  568.   return(_AL);
  569. }
  570.  
  571.  
  572. /**************************************************************************
  573.   void DSP_Write(BYTE output)
  574.  
  575.   DESCRIPTION: Writes a byte to the DSP
  576.  
  577. **************************************************************************/
  578. void DSP_Write(BYTE output)
  579. {
  580.   asm  mov dx,io_addr;               // dx holds the port address
  581.   asm  add dx,DSP_WSTATUS;
  582. loop:                                // wait for bit 7 to clear
  583.   asm    in al,dx;
  584.   asm    test al,0x80;
  585.   asm    jnz loop
  586.                                      // write our bute!
  587.   asm  mov dx,io_addr;
  588.   asm  add dx,DSP_WRITE;
  589.   asm  mov al,output
  590.   asm  out dx,al;
  591.  
  592. }
  593.  
  594.  
  595. /**************************************************************************
  596.   int get_sb_env()
  597.  
  598.   DESCRIPTION:  Get sound blaster information from the environment
  599.                 variable "BLASTER"
  600.  
  601. **************************************************************************/
  602. int get_sb_env(void)
  603. {
  604.   char *str;
  605.   int i;
  606.  
  607.   str=getenv("BLASTER");
  608.   if(!str) return(FALSE);                 // no blaster variable? go home
  609.  
  610.                                           // Convert string to upper case
  611.   for(i = 0 ; i < strlen(str); i++) *(str+i) = toupper(*(str+i));
  612.                                           // pick apart variable for info.
  613.                                           // Io address
  614.   for(i = 0; *(str+i) != 0 && *(str + i) != 'A'; i++);
  615.   if(*(str+i) == 0) return(FALSE);
  616.   sscanf(str+i+1,"%x",&io_addr);
  617.   if(io_addr<0x210 || io_addr>0x260) return (FALSE);
  618.  
  619.                                           // Dma channel number
  620.   for(i = 0; *(str+i) != 0 && *(str + i) != 'D'; i++);
  621.   if(*(str+i) == 0) return(FALSE);
  622.   sscanf(str+i+1,"%d",&dma_ch);
  623.   if(dma_ch > 7) return(FALSE);           // only 0-7 allowed
  624.  
  625.                                           // IRQ port number (?)
  626.   for(i = 0; *(str+i) != 0 && *(str + i) != 'I'; i++);
  627.   if(*(str+i) == 0) return(FALSE);
  628.   sscanf(str+i+1,"%d",&intnr);
  629.   if(intnr < 2  || intnr > 10) return (FALSE);
  630.  
  631.                                           // card_id
  632.   for(i = 0; *(str+i) != 0 && *(str + i) != 'T'; i++);
  633.   if(*(str+i) == 0) return(FALSE);
  634.   sscanf(str+i+1,"%d",&card_id);
  635.  
  636.   return(TRUE);
  637. }
  638.  
  639.  
  640.  
  641. /**************************************************************************
  642.   WORD DSP_GetVersion()
  643.  
  644.   DESCRIPTION:  Get the version number of the DSP
  645.  
  646. **************************************************************************/
  647. WORD DSP_GetVersion(void)
  648. {
  649.   DSP_Write(DSP_GET_VERS);
  650.   return((WORD)DSP_Read()*256+DSP_Read());
  651. }
  652.  
  653.  
  654. /*  ---------------  Misc.  Stuff ------------ */
  655.  
  656.  
  657.  
  658. /**************************************************************************
  659.   int CardCheck()
  660.  
  661.   DESCRIPTION:  Check for both FM chip and DSP
  662.  
  663. **************************************************************************/
  664. int CardCheck(void)
  665. {
  666.   int ret=0;
  667.  
  668.   if(FM_Detect()) ret|=FM_DETECT;
  669.   if(DSP_Reset()) ret|=DSP_DETECT;
  670.   return(ret);
  671. }
  672.  
  673.  
  674. /**************************************************************************
  675.   static void far interrupt testn_int()
  676.  
  677.   DESCRIPTION:  Function stored as an interrupt to test various interrrupt
  678.                 vectors by test_int()
  679.  
  680. **************************************************************************/
  681. static void far interrupt testn_int(void)
  682. {
  683.   tst_cnt++;
  684.  
  685.   asm mov dx,io_addr;
  686.   asm add dx,DSP_RSTATUS;
  687.   asm in al,dx;         /* Ack DSP interrupt */
  688.  
  689.   asm mov al,0x20;
  690.   asm out 0x20,al; /* set EOI */
  691.   asm mov bx,intnr
  692.   asm cmp bx,7
  693.   asm jbe end
  694.   asm out 0xa0,al; /* set EOI */
  695.  
  696. end:
  697. }
  698.  
  699.  
  700.  
  701. /**************************************************************************
  702.   static int test_int()
  703.  
  704.   DESCRIPTION:  This function is used by scan_int() to test interrupt
  705.                 stuff.  It installs a test interrupt in the
  706.                 requested spot (intnr) then sees if the DSP can
  707.                 use it.
  708.  
  709. **************************************************************************/
  710. static int test_int(void)
  711. {
  712.   int i;
  713.   BYTE int1,int2;
  714.  
  715.   orgint=getvect(int2vect(intnr));
  716.  
  717.   asm in al,0x21;   /* save org master intr settings */
  718.   asm mov int1,al;
  719.  
  720.   asm in al,0xa1;   /* save org slave intr settings */
  721.   asm mov int2,al;
  722.  
  723.   asm mov al,0xfe;
  724.   asm cli;
  725.   asm out 0x21,al;  /* disable ALL intr (except timer) */
  726.   asm mov al,0xff
  727.   asm out 0xa1,al;
  728.   asm sti;
  729.  
  730.   tst_cnt=0;                   // reset our test interrupt counter.
  731.  
  732.   enable_int(intnr);           // put in our test interrupt
  733.   setvect(int2vect(intnr),testn_int);
  734.  
  735.   DSP_Write(DSP_INVOKE_INTR);  /* still magic -- make DSP interrupt? */
  736.  
  737.   for(i=0;i<30000;i++) if(tst_cnt) break;
  738.  
  739.   asm cli;
  740.   asm mov al,int1;
  741.   asm out 0x21,al;  /* restore org master intr */
  742.  
  743.   asm mov al,int2;  /* restore org slave intr */
  744.   asm out 0xa1,al;
  745.   asm sti;
  746.   setvect(int2vect(intnr),orgint);
  747.  
  748.   if(i==30000) return(FALSE);
  749.   else return(TRUE);
  750. }
  751.  
  752.  
  753. /**************************************************************************
  754.   static int scan_int()
  755.  
  756.   DESCRIPTION: This makes sure that the interrupt number picked by the
  757.                 IRQ specification is a good choice.
  758.  
  759. **************************************************************************/
  760. static int scan_int(void)
  761. {
  762.   int i;
  763.  
  764.   if(test_int()) return(intnr);   // Original choice good?
  765.  
  766.   for(i=0;i<5;i++)                // Try our five best guesses
  767.   {
  768.     intnr=intrx[i];
  769.     if(test_int()) return(i);
  770.   }
  771.   return(0);
  772. }
  773.  
  774.  
  775. /**************************************************************************
  776.   static cardtype CheckHard()
  777.  
  778.   DESCRIPTION:  Checks hardware for DSP and FM chip
  779.  
  780. **************************************************************************/
  781. static cardtype CheckHard(void)
  782. {
  783.   int ret;
  784.  
  785.   ret=DSP_Reset();
  786.   if(ret)
  787.   {
  788.     if(!scan_int()) {              // Scan IRQ's
  789.       sberr= irqerr;
  790.       return(none);
  791.     }
  792.  
  793.     fm_addr=io_addr+FM_BOTH_OFF;
  794.     if(!FM_Detect()) {
  795.       sberr = fmerr;
  796.       return(none);                 /* no fm? -> damaged! */
  797.     }
  798.  
  799.                                    // SBPro  checking here.  Not too critical
  800. /*    fm_both=fm_addr;
  801.     fm_addr=io_addr+FM_RIGHT_OFF;
  802.     fm_right=fm_addr;
  803.     ret3=FM_Detect();
  804.     fm_addr=fm_both;
  805.  
  806.     if(ret3)
  807.     {
  808.       wh_card=sbpro;
  809.       fm_left=io_addr+FM_LEFT_OFF;
  810.     }
  811.     else wh_card=sb20;  */
  812.     wh_card = sb20;
  813.     return(wh_card);
  814.   }
  815.   sberr = nodsperr;
  816.   return(none);
  817. }
  818.  
  819.  
  820. /**************************************************************************
  821.   cardtype WhichCard()
  822.  
  823.   DESCRIPTION:  Calls various functions to make sure you've
  824.                 got a Sound Blaster
  825.  
  826. **************************************************************************/
  827. cardtype WhichCard(void)
  828. {
  829.   cardtype cret;
  830.   int i;
  831.  
  832.   if(get_sb_env()) cret=CheckHard();    // grab environment variable
  833.   if(cret!=nodsp) return(cret);         // If dsp is there, then go home
  834.  
  835.   intnr=7;
  836.   for(i=0;i<6;i++)                      // scan around for a better io address
  837.   {
  838.     io_addr=ioaddr[i];
  839.  
  840.     cret=CheckHard();
  841.     if(cret!=nodsp) return(cret);
  842.   }
  843.   return(none);                         // Uh oh.
  844. }
  845.  
  846.  
  847. /**************************************************************************
  848.   int SB_Setup()
  849.  
  850.   DESCRIPTION: Sets up the sound blaster for action.  This is the only
  851.                function a programmer should really use.  Most of the
  852.                nitty gritty is handled internally.
  853.  
  854. **************************************************************************/
  855. int SB_Setup(void)
  856. {
  857.   int i;
  858.  
  859.   InitT2();                      /* init Timer 2 */
  860.   measure();                     /* time loop factor */
  861.   mue3=mcalc(3) ;               /* calc val for 3 micro sec delay */
  862.   mue23=mcalc(23) ;             /* calc val for 23 micro sec delay */
  863.  
  864.   WhichCard();
  865.   if(wh_card==none) return(FALSE);
  866.  
  867.   if(wh_card==sb20 || wh_card==sbpro)
  868.   {                             // Get DSP ready
  869.     dsp_vers=DSP_GetVersion();
  870.     DSP_Write(DSP_SPKR_ON);
  871.   }
  872.  
  873.                                 // Allocate space for Mixing buffer
  874.   dma_buffer = (BYTE far *)farmalloc(dma_bufferlen+5);
  875.   if(!dma_buffer) {
  876.     sberr = nomem;
  877.     return(FALSE);
  878.   }
  879.                                 // Clear the buffer
  880.   for(i = 0; i < dma_bufferlen+4; i++) {
  881.     *(dma_buffer+i) = 0;
  882.   }
  883.   SetRate(11000);               // Set the sample rate
  884.  
  885.    return(TRUE);
  886. }
  887.  
  888.  
  889. /**************************************************************************
  890.   DWORD far2long(char far *adr)
  891.  
  892.   DESCRIPTION: This is used by dma_set to convert a regular far address
  893.                to a 20 bit flat address.
  894.  
  895. **************************************************************************/
  896. DWORD far2long(char far *adr)
  897. {
  898.   return(((DWORD)FP_SEG(adr)<<4)+FP_OFF(adr));
  899. }
  900.  
  901.  
  902. /**************************************************************************
  903.   void SetRate(WORD rate)
  904.  
  905.   DESCRIPTION:  Sets the sample rate (specified in hz)
  906.  
  907. **************************************************************************/
  908. void SetRate(WORD rate)
  909. {
  910.   DWORD val;
  911.  
  912.   if(rate<4000) return;               // Calculate number for the sound card
  913.   val=256-1000000L/rate;
  914.   DSP_Write(DSP_SAMPLE_RATE);
  915.   DSP_Write((BYTE)val);
  916.  
  917.   sample_rate = rate;                 // FYI
  918. }
  919.  
  920. /**************************************************************************
  921.   WORD dma_set(DWORD adrl,WORD len,int channel)
  922.  
  923.   DESCRIPTION:  This programs the DMA controller to start a single pass
  924.                 output transfer.
  925.  
  926.                 (Draeden of VLA has provided some good information for
  927.                 DMA programming in his INTRO to DMA document)
  928.  
  929. **************************************************************************/
  930. void dma_set(BYTE far *sound_address,WORD len,BYTE channel)
  931. {
  932.   WORD adr;
  933.   DWORD adrl;
  934.   BYTE page;
  935.  
  936.   adrl = far2long(sound_address); // convert address to 20 bit format
  937.   adr=(WORD)adrl;                 // extract page address
  938.   page=(BYTE)(adrl>>16);          // extract page number
  939.  
  940.                                   // PREPARE DMA.
  941.                                   //   (Channels 0-3 have different command
  942.                                   //    ports than 4-7.)
  943.  
  944.   if(channel < 4) {               // channels 0-3?
  945.     asm {
  946.                                   // SET THE CHANNEL MASK BIT
  947.       mov  al,04                   // set 3rd bit
  948.       add al,channel
  949.       out 0x0a,al                 // write the channel
  950.  
  951.       mov al,0
  952.       out 0x0c,al                  // Clear the byte pointer
  953.  
  954.       mov al,0x58                  // Read mode  (was 48)
  955.       add al,channel
  956.       out 0x0b,al                  // set the mode
  957.     }
  958.   }
  959.   else {                          // channels 4-7?
  960.     asm {
  961.                                   // SET THE CHANNEL MASK BIT
  962.       mov al,channel              // (no need to set third bit)
  963.       out 0xd4,al                 // write the channel
  964.  
  965.       mov al,0
  966.       out 0xd8,al                  // Clear the byte pointer
  967.  
  968.       mov al,0x58                  // Read mode
  969.       add al,channel
  970.       out 0xd6,al                  // set the mode
  971.     }
  972.   }
  973.  
  974.                                   // OK.  Now the transfer info
  975.                                   // WRITE THE ADDRESS OF THE DATA
  976.   _DX = dma_adr[channel];         // Set the address port
  977.   asm {
  978.     mov ax,adr
  979.     out dx,al                     // Write address low byte
  980.     mov al,ah
  981.     out dx,al                     // write address high byte
  982.   }
  983.  
  984.   _DX = dma_page[channel];        // Set the page port
  985.   asm {
  986.     mov al,page
  987.     out dx,al                      // Write the page byte
  988.   }
  989.                                   // WRITE THE LENGTH OF THE DATA
  990.   _DX = dma_len[channel];          // Set the length port
  991.   asm {
  992.     mov ax,len
  993.     out dx,al                     // Write length low byte
  994.     mov al,ah
  995.     out dx,al                     // write length high byte
  996.   }
  997.  
  998.                                   // WRITE THE PAGE LOCATION OF THE DATA
  999.                                   // CLEAR THE CHANNEL MASK BIT
  1000.   if(channel < 4) {
  1001.     asm {
  1002.       mov al,channel              // (mask bit already clear)
  1003.       out 0x0a,al                 // write the channel
  1004.     }
  1005.   }
  1006.   else {
  1007.     asm {
  1008.       mov al,channel
  1009.       and al,0x03                  // Clear the mask bit
  1010.       out 0x0a,al                 // write the channel
  1011.     }
  1012.   }
  1013. }
  1014.  
  1015. /**************************************************************************
  1016.   void polldma(BYTE channel)
  1017.  
  1018.   DESCRIPTION:  This function poles the DMA controller to find out how many
  1019.                 bytes are left in the current transfer.
  1020.  
  1021.                 As of version 0.4, this function is no long used, but
  1022.                 I thought it might be useful to someone else, so I've only
  1023.                 commented it out.
  1024. **************************************************************************/
  1025. /*WORD polldma(BYTE channel)
  1026. {
  1027.   BYTE low1,high1,low2,high2;
  1028.  
  1029.   disable_int(intnr);             // Turn off the interrupt so we don't get
  1030.                                   // caught with our pants down.
  1031.   asm {
  1032.     mov dx,0x0c                   // Flip the master reset switch
  1033.     mov al,0
  1034.     out dx,al
  1035.   }
  1036.   _DX = dma_len[channel];         // Load in the counter address
  1037.                                   // read position twice, becasue sometimes
  1038.                                   // there is a problem
  1039.   asm{
  1040.     in al,dx                      // read the low byte first
  1041.     mov low1,al
  1042.     in al,dx                      // read the high byte next
  1043.     mov high1,al
  1044.  
  1045.     in al,dx                      // read the low byte first
  1046.     mov low2,al
  1047.     in al,dx                      // read the high byte next
  1048.     mov high2,al
  1049.  
  1050.   }
  1051.   enable_int(intnr);              // Done, so we'll put the interrupt back.
  1052.  
  1053.                                   // High bytes the same? Use second reading
  1054.   if(high1 == high2)return((WORD)high2*256+low2);
  1055.                                   // else the First reading is accurate
  1056.   return(high1*256+low1);
  1057.  
  1058. }*/
  1059.  
  1060.  
  1061. /**************************************************************************
  1062.   static void far interrupt sb_int()
  1063.  
  1064.   DESCRIPTION:  This is the sound Blaster interrupt that is to be
  1065.                 called at the end of DMA transfer.  This software is
  1066.                 set up for a continual DMA transfer, so all it does
  1067.                 is have the DMA transfer start all over again.
  1068.  
  1069. **************************************************************************/
  1070. static void far interrupt sb_int(void)
  1071. {
  1072.   int d,i,j;
  1073.   static long int midi_count = 100;
  1074.   static int dma_pos=0;
  1075.  
  1076.   if(DSP_overhead) timer_on();     // start timer to measure DSP overhead
  1077.  
  1078.  
  1079.                                    // SAMPLE MIXER
  1080.                                    // Write data to the dma buffer
  1081.   for(dma_pos = 0; dma_pos < dma_bufferlen+1; dma_pos++) {
  1082.     d = 128;                       // reset data holder
  1083.  
  1084.     for(i = 0; i < sounds_in_queue; i++) {
  1085.       d += *(sounddata[i]++);       // accumulate data
  1086.       soundpos[i]--;                // move to next byte
  1087.       if(!soundpos[i]) {           // Sound done?
  1088.                                    // Clear the slot and scoot sounds left
  1089.         for(j = i; j < sounds_in_queue;j++) {
  1090.           sounddata[j] = sounddata[j+1];
  1091.           soundpos[j] = soundpos[j+1];
  1092.         }
  1093.         sounds_in_queue--;
  1094.       }
  1095.     }
  1096.     if(d>255) d = 255;             // clip the output byte
  1097.     if(d<0) d = 0;
  1098.  
  1099.     *(dma_buffer + dma_pos) = d;   // Write data to the buffer
  1100.   }
  1101.   *(dma_buffer) = d;               //  This prevents the popping sound
  1102.                                    // That can happen when the buffer is
  1103.                                    // suddenly reset
  1104.  
  1105.                                    // acknowledge DSP interrupt
  1106.   asm mov dx,io_addr;
  1107.   asm add dx,DSP_RSTATUS;
  1108.   asm in al,dx;
  1109.  
  1110.  
  1111.                                    // reset interrupt
  1112.   asm mov al,0x20;
  1113.   asm out 0x20,al; /* set EOI */
  1114.   asm mov bx,intnr
  1115.   asm cmp bx,7
  1116.   asm jbe end
  1117.   asm out 0xa0,al; /* set EOI */
  1118. end:
  1119.                                    // Varmint's system clock
  1120.   vclock ++;
  1121.  
  1122.                                    // MIDI stuff first
  1123.   midi_count-= 100;
  1124.   if(midi_count < 100) {
  1125.     MidiPlayer();                  // Call a midi player
  1126.     midi_count += midi_callfreq * midi_usertempo*100.0; // reset counter
  1127.     debugnum =midi_usertempo * 100;
  1128.   }
  1129.  
  1130.   if(DSP_overhead) DSP_overhead = timer_off();//  How long did this take?
  1131. }
  1132.  
  1133.  
  1134.  
  1135.  
  1136. /**************************************************************************
  1137.   void SB_SetVect()
  1138.  
  1139.   DESCRIPTION:  Installs the DMA interrupt vector.  This makes it so that
  1140.                 sb_int() is called whenever a DMA transfer is finished
  1141.  
  1142. **************************************************************************/
  1143. void SB_SetVect(void)
  1144. {
  1145.   orgirqint=getvect(int2vect(intnr));
  1146.   setvect(int2vect(intnr),sb_int);     /* set vector to our routine */
  1147.   enable_int(intnr);                   /* enable sb interrupt */
  1148. }
  1149.  
  1150.  
  1151. /**************************************************************************
  1152.   void SB_RemoveVect()
  1153.  
  1154.   DESCRIPTION:  Removes the DMA interrupt vector
  1155.  
  1156. **************************************************************************/
  1157. void SB_RemoveVect(void)
  1158. {
  1159.   disable_int(intnr);                     /* disable sb interrupt */
  1160.   setvect(int2vect(intnr),orgirqint);      /* restore org intr vector */
  1161. }
  1162.  
  1163.  
  1164. /* --------------------------------------------------- */
  1165.  
  1166. /* timerX routines are following
  1167.  
  1168.   These routines are for highly accurate time measurements
  1169.  
  1170. */
  1171.  
  1172.  
  1173. /**************************************************************************
  1174.   void InitT2()
  1175.  
  1176.   DESCRIPTION: Initializes speaker timer for timing operations.
  1177.  
  1178. **************************************************************************/
  1179. void InitT2(void)
  1180. {
  1181.   asm in al,0x61   /* no signal on speaker! */
  1182.   asm and al,0xfd
  1183.   asm or  al,1
  1184.   asm out 0x61,al
  1185.  
  1186.   asm mov al,0xb4  /* program timer 2 with modus 2 */
  1187.   asm out 0x43,al  /* and counter value of 0 (2^16)*/
  1188.   asm mov al,0
  1189.   asm out 0x42,al
  1190.   asm out 0x42,al
  1191. }
  1192.  
  1193.  
  1194. /**************************************************************************
  1195.   void timer_on()
  1196.  
  1197.   DESCRIPTION: Turns on timer counter for a time measurement
  1198.  
  1199. **************************************************************************/
  1200. void timer_on(void)
  1201. {
  1202.   asm mov al,0x80;  /* latch timer 2 */
  1203.   asm out 0x43,al;  /* save value in timer_hold */
  1204.   asm in al,0x42;
  1205.   asm mov bl,al;
  1206.   asm in al,0x42;
  1207.   asm mov bh,al;
  1208.   asm mov timer_hold,bx;
  1209. }
  1210.  
  1211.  
  1212. /**************************************************************************
  1213.   WORD timer_off()
  1214.  
  1215.   DESCRIPTION: Turns off time and reports clicks elapsed.  Note that this
  1216.                timer is so quick that it is wraps after only 56
  1217.                milliseconds.  If you want to timer longer stuff, I suggest
  1218.                using the global variable vclock.  It's tick frequency is
  1219.                sample_rate / dma_bufferlen.
  1220.  
  1221. **************************************************************************/
  1222. WORD timer_off(void)
  1223. {
  1224.   asm mov al,0x80; /* latch timer 2 */
  1225.   asm out 0x43,al;
  1226.   asm in al,0x42;
  1227.   asm mov ah,al;
  1228.   asm in al,0x42;
  1229.   asm xchg ah,al;
  1230.   asm mov bx,timer_hold;
  1231.   asm sub ax,bx;
  1232.   asm neg ax;
  1233.   asm mov timer_diff,ax; /* calc timer_hold - ax to timer_diff */
  1234.   return(_AX);
  1235. }
  1236.  
  1237.  
  1238. /**************************************************************************
  1239.   WORD to_micro(WORD clk)
  1240.  
  1241.   DESCRIPTION: Converts clock ticks number to microsecs
  1242.  
  1243. **************************************************************************/
  1244. WORD to_micro(WORD clk)
  1245. {
  1246.     return(clk*838/1000);
  1247. }
  1248.  
  1249.  
  1250. /**************************************************************************
  1251.   void clkdelay(WORD clicks)
  1252.  
  1253.   DESCRIPTION: Wait specified number of clock ticks
  1254.  
  1255. **************************************************************************/
  1256. void clkdelay(WORD clicks)
  1257. {
  1258.   asm mov al,0x80;  /* latch timer 2 */
  1259.   asm out 0x43,al;  /* save value in bx */
  1260.   asm in al,0x42;
  1261.   asm mov bl,al;
  1262.   asm in al,0x42;
  1263.   asm mov bh,al;
  1264. loop:
  1265.   asm mov al,0x80;
  1266.   asm out 0x43,al;
  1267.   asm in al,0x42;
  1268.   asm mov ah,al;
  1269.   asm in al,0x42;
  1270.   asm xchg ah,al;
  1271.   asm sub ax,bx;
  1272.   asm neg ax;
  1273.   asm cmp ax,clicks;  /* leave routine after click CLK's */
  1274.   asm jle loop;
  1275. }
  1276.  
  1277.  
  1278. /**************************************************************************
  1279.   void measure()
  1280.  
  1281.   DESCRIPTION: measures a standard delay loop for other delay functions
  1282.  
  1283. **************************************************************************/
  1284. void measure(void)
  1285. {
  1286.   timer_on();
  1287.  
  1288.   asm cli
  1289.   asm mov cx,10000  /* internal test loop */
  1290. loop1:
  1291.   asm loop loop1
  1292.  
  1293.   timer_off();
  1294.   asm sti
  1295.   timer_val=timer_diff;
  1296.  
  1297.   mue999=mcalc(999); /* calc for msdelay */
  1298. }
  1299.  
  1300.  
  1301. /**************************************************************************
  1302.   void mdelay(WORD delay)
  1303.  
  1304.   DESCRIPTION: Very tiny delay
  1305.  
  1306. **************************************************************************/
  1307. void mdelay(WORD delay)
  1308. {
  1309.   asm mov cx,delay
  1310.  loop1:
  1311.   asm loop loop1
  1312. }
  1313.  
  1314.  
  1315. /**************************************************************************
  1316.   void _saveregs msdelay(WORD delay)
  1317.  
  1318.   DESCRIPTION:  Millisec delay.  When using this library, you should use this
  1319.                 delay for millisecond delays instead of the delay
  1320.                 functions that comes with turbo C.
  1321.  
  1322. **************************************************************************/
  1323. void _saveregs msdelay(WORD delay)
  1324. {
  1325.   WORD i;
  1326.  
  1327.   for(i=0;i<delay;i++) mdelay(mue999); /* only 999 cause of fnctn call */
  1328. }
  1329.  
  1330.  
  1331. /**************************************************************************
  1332.   WORD mcalc(WORD micro)
  1333.  
  1334.   DESCRIPTION:  Calculates number of ticks to send to mdelay for a specified
  1335.   number of microseconds.
  1336.  
  1337. **************************************************************************/
  1338. WORD mcalc(WORD micro)
  1339. {
  1340.   return(WORD)((long)micro*10000L/timer_val*1000/838);
  1341. }
  1342.  
  1343.                                       /********************************
  1344.  
  1345.                                                 TIMER 0 STUFF
  1346.  
  1347.  
  1348.  
  1349.  
  1350.                                       *********************************/
  1351. /* --------------------------------
  1352.  
  1353. CAUTION: These routines can cause a lot of headaches while debugging.
  1354. If you set your own interrupt and then stop the program before you call
  1355. Remove_Timer0(), you'd better reboot your computer, because very
  1356. unpredictable things will happen if Install_Timer0() is called again.
  1357. My suggestion is to get your interrupt working and then comment out the
  1358. Timer0 routines until the rest of the program is written and debugged.
  1359.                                       - Eric  */
  1360.  
  1361. /**************************************************************************
  1362.   static void interrupt timerint()
  1363.  
  1364.   DESCRIPTION: THis is the actual interrupt function stored in the timer
  1365.                0 slot (int 08).   This calls the old int08 function
  1366.                at proper intervals as well as the user specified function
  1367.  
  1368. **************************************************************************/
  1369. static void interrupt timerint(void)
  1370. {
  1371.  
  1372.   timer_on();                      // set timer for overhead calculation.
  1373.   call_func();                     // user specified function
  1374.   DSP_overhead = timer_off();      // Get the time (in clicks) it took
  1375.  
  1376.                                    // Now let's do some fancy counting so
  1377.                                    // we can call the system clock at the
  1378.                                    // right moments.
  1379.   if(timsum<100)
  1380.   {
  1381.     timsum+=timadd;
  1382.     orgtick();
  1383.   }
  1384.   else
  1385.   {
  1386.     asm mov al,0x20;
  1387.     asm out 0x20,al;
  1388.   }
  1389.   timsum-=100;                     // decrement our special timer
  1390. }
  1391.  
  1392.  
  1393. /**************************************************************************
  1394.   void Install_Timer0(WORD period,void far (*func)())
  1395.  
  1396.   DESCRIPTION: This sets up timer0 to call your function at the specified
  1397.                period.
  1398.  
  1399. **************************************************************************/
  1400. void Install_Timer0(WORD period,void far (*func)(void))
  1401. {
  1402.    if(!func) return;       /* no valid func ptr */
  1403.   call_func=func;
  1404.  
  1405.   timadd= (WORD)(6553600L/period); // counting seed for timerint()
  1406.   timsum=0;                 // start counter at 0
  1407.   interrupt_time_period = period / 1193180.0 ;
  1408.  
  1409.   asm mov al,0x36            /* program timer 0 with modus 3 */
  1410.   asm out 0x43,al            /* and counter value of period  */
  1411.   asm mov ax,period
  1412.   asm out 0x40,al
  1413.   asm mov al,ah
  1414.   asm out 0x40,al
  1415.  
  1416.   orgtick= getvect(8);       // Remember the old interrupt
  1417.   setvect(8,timerint);      // put in a new one.
  1418. }
  1419.  
  1420.  
  1421. /**************************************************************************
  1422.   void Remove_Timer0()
  1423.  
  1424.   DESCRIPTION:  Removes your goofy interrupt, 'cause we didn't want
  1425.                 it anyway!  :P
  1426.  
  1427. **************************************************************************/
  1428. void Remove_Timer0(void)
  1429. {
  1430.   if(!orgtick) return;      // Must have called Install_Timer0 first
  1431.   asm mov al,0x36            /* program timer 0 with modus 3 */
  1432.   asm out 0x43,al            /* and counter value of 0 (2^16)*/
  1433.   asm mov al,0
  1434.   asm out 0x40,al
  1435.   asm out 0x40,al
  1436.   setvect(8,orgtick);       // put back original vector
  1437. }
  1438.  
  1439.  
  1440.  
  1441. /**************************************************************************
  1442.   BYTE int2vect(BYTE intnr)
  1443.  
  1444.   DESCRIPTION:  This function converts a PIC irq number to a true
  1445.                 interrupt vector number.  For PC's with a 286 or greater,
  1446.                 irq's 0-7  refer to interrupts 0x08 - 0x0F and
  1447.                 irq's 8-15 refer to interrupts 0x70 - 0x77.
  1448.  
  1449. **************************************************************************/
  1450. BYTE int2vect(BYTE intnr)
  1451. {
  1452.   if(intnr>7) return(intnr + 0x68);
  1453.   else return(intnr+8);
  1454. }
  1455.  
  1456.  
  1457. /**************************************************************************
  1458.   void enable_int(BYTE nr)
  1459.  
  1460.   DESCRIPTION:  Enables an IRQ interrupt using the Programmable
  1461.                 interrupt controller (PIC)
  1462.  
  1463. **************************************************************************/
  1464. void enable_int(BYTE nr)
  1465. {
  1466.   if(nr>7)                     /* use 2nd intr controller? */
  1467.   {
  1468.     asm in al,0xa1;           // Read the PIC status from 0xa1
  1469.     asm mov cl,nr;            // load the interrupt number in the counter
  1470.     asm sub cl,8              // subract 8 to get the bit location right
  1471.     asm mov bl,1;             // load a 1 to bl
  1472.                               /* calc correct mask */
  1473.     asm shl bl,cl;            // Bitshift left bl by cl
  1474.     asm not bl;               // calculate the compliment
  1475.     asm and al,bl;            // leave a hole
  1476.     asm out 0xa1,al;          // write the result to the port
  1477.   }
  1478.   else
  1479.   {
  1480.     asm in al,0x21;
  1481.     asm mov cl,nr;
  1482.     asm mov bl,1;
  1483.     asm shl bl,cl; /* calc correct mask */
  1484.     asm not bl;
  1485.     asm and al,bl;
  1486.     asm out 0x21,al;
  1487.   }
  1488. }
  1489.  
  1490.  
  1491. /**************************************************************************
  1492.   void disable_int(BYTE nr)
  1493.  
  1494.   DESCRIPTION:  Disables an IRQ interrupt using the Programmable
  1495.                 interrupt controller.
  1496.  
  1497. **************************************************************************/
  1498. void disable_int(BYTE nr)
  1499. {
  1500.   if(nr>7)
  1501.   {
  1502.     asm in al,0xa1;    /* use 2nd intr controller? */
  1503.     asm mov cl,nr;
  1504.     asm sub cl,8
  1505.     asm mov bl,1;
  1506.     asm shl bl,cl;    /* calc correct mask */
  1507.     asm or al,bl;
  1508.     asm out 0xa1,al;
  1509.   }
  1510.   else
  1511.   {
  1512.     asm in al,0x21;
  1513.     asm mov cl,nr;
  1514.     asm mov bl,1;
  1515.     asm shl bl,cl;    /* calc correct mask */
  1516.     asm or al,bl;
  1517.     asm out 0x21,al;
  1518.   }
  1519. }
  1520.  
  1521.  
  1522. /**************************************************************************
  1523.   int getvoice(VOICE v[],int track,int channel, int note)
  1524.  
  1525.   DESCRIPTION: Find the first matching voice (or first inactive voice if
  1526.                 a match is not found).   This function is used by the midi
  1527.                 routine as an interface to get FM voices.
  1528.  
  1529. **************************************************************************/
  1530. int getvoice(VOICE v[],int track,int channel, int note)
  1531. {
  1532.   int i;
  1533.  
  1534.   for(i = 0; i < 9; i++) {              // find matching active note
  1535.     if(v[i].active) {
  1536.       if(v[i].owner_track == track &&
  1537.          v[i].owner_channel == channel &&
  1538.          v[i].note == note) return(i);
  1539.  
  1540.     }
  1541.   }
  1542.                                         // no note, so find first inactive voice
  1543.  
  1544.   for(i = 0; i < 9; i++) {
  1545.     if(!v[i].active) return(i);
  1546.   }
  1547.                                         // no available voices... error
  1548.   return -1;
  1549. }
  1550.  
  1551. /**************************************************************************
  1552.   MidiPlayer()
  1553.  
  1554.   DESCRIPTION: Routine for playing midi files.  THis is designed to be
  1555.                called from a timer interrupt.  To use, set these values
  1556.                in this order:
  1557.  
  1558.                    midi_data    (must point to a filled MIDI structure.)
  1559.                   midi_reset = TRUE;
  1560.                   midi_on = TRUE;
  1561.  
  1562.                The interrupt should pick up from there.
  1563.  
  1564.                It is easy to add functionality to this routine.  I've
  1565.                already included code to flag a wide variety of MIDI
  1566.                events, so all you have to do is add your own code under
  1567.                the point an event is flagged.  I've left a bunch of
  1568.                commented print statements in to help make the code
  1569.                more readable and provide cues for accessing the data.
  1570.  
  1571.  
  1572.                ***  WARNING  ***
  1573.  
  1574.                If you add your own code here, make sure that it doesn't
  1575.                take more than a few milliseconds to execute.  If
  1576.                MidiPlayer() is called again by the interrupt before your
  1577.                code is done, your whole program will probably crash.
  1578.  
  1579. **************************************************************************/
  1580. void MidiPlayer(void)
  1581. {
  1582.   static VOICE v[9];                    // Nine FM voices
  1583.   VOICE vh[9];                          // waiting list
  1584.   int vhold = 0;
  1585.   static int i,j,live_tracks,vidx;
  1586.   static int divisions = 96,ms_per_div=5000;
  1587.   static BYTE event,ev,ch,b1,b2,etype,track_on[16];
  1588.   static last_ev[16];
  1589.   static long int trkloc[16],itmr,length,l2;
  1590.   static float tmr[16];
  1591.   static char tdata[256];
  1592.   // static float beat_ratio = 1.0;
  1593.  
  1594.   if(!midi_data) {                      // must have data to play!
  1595.     midi_on = FALSE;
  1596.     return;
  1597.   }
  1598.   if(midi_reset) {                       // Reset?  zero track pointers and timers
  1599.     for(i = 0; i < 16; i++ ) {
  1600.       trkloc[i] = 1;                    // no need to read first time offset
  1601.       tmr[i] = 0;                       // all timers start at zero
  1602.       track_on[i] = TRUE;
  1603.       if(i < 9) v[i].active = 0;        // unreserve all voices
  1604.       last_ev[i] = 0x80;                // set last event to note off
  1605.     }
  1606.     midi_reset = 0;                     // clear midi reset flag
  1607.     live_tracks = midi_data->num_tracks;// set number of active tracks so
  1608.                                         // we know when to stop.
  1609.     divisions = midi_data->divisions;   // ticks per quarter note
  1610.     if(divisions < 0) divisions = -divisions;  // some midi files have
  1611.                                                // negative division values
  1612.   }
  1613.  
  1614.   if(!midi_on) return;                   // logical switch for midi on/off
  1615.  
  1616.  
  1617.   for(i = 0 ; i < midi_data->num_tracks; i++) {  // loop over tracks
  1618.     while(tmr[i] <= 0) {                // Process while timer is 0;
  1619.       event = *(TD);                    // get next event (TD is a macro)
  1620.       trkloc[i]++;                      // advance track location pointer
  1621.  
  1622.       if(event == 0xFF) {                 // META event?
  1623.         etype = *(TD);
  1624.         trkloc[i] ++;
  1625.         trkloc[i] += ReadVarLen(TD,&length); // read length of meta event
  1626.                                        // grab any text data for text events
  1627.         for(j = 0; j < length; j++) tdata[j] = *(TD + j);
  1628.         tdata[j] = 0;
  1629.  
  1630.         switch(etype) {
  1631.           case 0x00:
  1632.             j = *(TD)*256 + *(TD+1);
  1633.             //printf("[%d] SEQUENCE NUMBER (%d)\n",i,j);
  1634.             break;
  1635.           case 0x01:
  1636.             //printf("[%d] TEXT EVENT (%s)\n",i,tdata);
  1637.             break;
  1638.           case 0x02:
  1639.             //printf("[%d] COPYWRITE EVENT (%s)\n",i,tdata);
  1640.             break;
  1641.           case 0x03:
  1642.             //printf("[%d] TRACK NAME EVENT (%s)\n",i,tdata);
  1643.             break;
  1644.           case 0x04:
  1645.             //printf("[%d] INSTRUMENT NAME EVENT (%s)\n",i,tdata);
  1646.             break;
  1647.           case 0x05:
  1648.             //printf("[%d] LYRIC EVENT (%s)\n",i,tdata);
  1649.             break;
  1650.           case 0x06:
  1651.             //printf("[%d] MARKER EVENT (%s)\n",i,tdata);
  1652.             break;
  1653.           case 0x07:
  1654.             //printf("[%d] CUE EVENT (%s)\n",i,tdata);
  1655.             break;
  1656.            case 0x2f:                   // End of track
  1657.             //printf("[%d] END OF TRACK\n",i);
  1658.             tmr[i] = MAXFLOAT;               // set timer to highest value
  1659.             track_on[i] = FALSE;       // turn off track
  1660.             live_tracks--;             // decrement track counter
  1661.             if(live_tracks == 0) {     // last track?  Turn off midi!
  1662.               midi_on = FALSE;
  1663.               midi_reset = TRUE;       // Make sure we start over
  1664.               return;
  1665.             }
  1666.             break;
  1667.           case 0x51:                   // TEMPO event (microsecs per 1/4 note)
  1668.             l2 = *(TD) * 0x10000L + *(TD+1) * 0x100 + *(TD+2);
  1669.             //printf("[%d] TEMPO EVENT (%ld)\n",i,l2);
  1670.             ms_per_div = (int)(l2/divisions);
  1671.                                        // Convert number to a counter used
  1672.                                        // by an 183 Hhz interrupt.
  1673.             midi_callfreq = ms_per_div/5454.0;
  1674.             break;
  1675.           case 0x58:
  1676.             //printf("[%d] TIME SIG EVENT (%X,%X,%X,%X)\n",i,
  1677.             //        *(TD),*(TD+1),*(TD+2),*(TD+3));
  1678.             break;
  1679.           case 0x59:
  1680.             //printf("[%d] KEY SIG EVENT (%X,%X)\n",i,*(TD),*(TD+1));
  1681.             break;
  1682.           case 0x7F:
  1683.             //printf("[%d] SEQUENCER DATA EVENT\n",i);
  1684.             break;
  1685.           default:
  1686.             //printf("[%d] *** undefined event *** (%X,type: %X,length %ld)\n",i,event,etype,length);
  1687.             break;
  1688.         }
  1689.         trkloc[i] += length;
  1690.       }
  1691.       else if(event == 0xF0 || event == 0xF7) { // sysex event
  1692.         trkloc[i] += ReadVarLen(TD,&length);
  1693.         //printf("Sysex type 1 [length: %ld]\n",length);
  1694.         trkloc[i] += length;
  1695.       }
  1696.       else {                           // PROCESS MIDI EVENTS
  1697.  
  1698.         if(!(event & 0x80)) {          // top bit Not set? Running status!
  1699.           b1 = event;                  // b1 = note   (usually)
  1700.           b2 = *(TD + 1);              // b2 = volume? (usually)
  1701.           event = last_ev[i];          // use last event
  1702.           //printf("Running status >>");
  1703.           //for(j = 0; j < 9; j++) printf("%d",v[j].active);
  1704.           //printf("\n");
  1705.           trkloc[i] --;                // one less byte for running status.
  1706.         }
  1707.         else {                         // Else it was a regular event
  1708.           last_ev[i] = event;          // set to last event
  1709.           b1 = *(TD);                   // get next two bytes
  1710.           b2 = *(TD+1);
  1711.         }
  1712.         ev = event & 0xF0;             // strip lower four bits
  1713.         ch = event & 0x0f;             // channel
  1714.         vidx = getvoice(v,i,ch,b1);    // Get a voice index
  1715.  
  1716.         switch(ev) {
  1717.           case 0x80:                   // Note off
  1718.             //printf("[%d] Note off (%d,%d)",i,b1,b2);
  1719.             trkloc[i] += 2;
  1720.             if(vidx > -1) {            // If a matching voice was found,
  1721.                                        // kill it.
  1722.               FM_KeyOff(vidx);
  1723.               FM_SetVol(vidx,0);
  1724.               v[vidx].active = FALSE;
  1725.             }
  1726.             break;
  1727.           case 0x90:                   // Note On
  1728.             //printf("[%d] Note on (%X,%d,%d)",i,event,b1,b2);
  1729.             trkloc[i] += 2;
  1730.             if(vidx > -1) {            // Voice found?
  1731.               if(v[vidx].active) {     // already active? Turn it off.
  1732.                 v[vidx].active = FALSE;
  1733.                 FM_KeyOff(vidx);
  1734.                 FM_SetVol(vidx,0);
  1735.               }
  1736.               else {                   // Wasn't active?  Turn it on.
  1737.                 v[vidx].owner_track = i;
  1738.                 v[vidx].owner_channel = ch;
  1739.                 v[vidx].note = b1;
  1740.                 v[vidx].volume = b2;
  1741.                 v[vidx].active = TRUE;
  1742.                 FM_SetNote(vidx,b1);
  1743.                 FM_SetVol(vidx,music_volume);
  1744.                 FM_KeyOn(vidx);
  1745.               }
  1746.             }
  1747.             else {                     // There might be space later
  1748.                                        // store our note
  1749.               vh[vhold].owner_track = i;
  1750.               vh[vhold].owner_channel = ch;
  1751.               vh[vhold].note = b1;
  1752.               vh[vhold].volume = b2;
  1753.               vhold ++;
  1754.               if(vhold >8) vhold = 8;  //  Only nine hold notes considered
  1755.             }
  1756.             break;
  1757.           case 0xA0:                   // Key pressure
  1758.             //printf("[%d] Note presure (%d,%d)\n",i,b1,b2);
  1759.             trkloc[i] += 2;
  1760.             break;
  1761.           case 0xB0:                   // Control CHange
  1762.             //printf("[%d] Control Change (%d,%d)\n",i,b1,b2);
  1763.             trkloc[i] += 2;
  1764.             break;
  1765.           case 0xC0:                   // Program change
  1766.             //printf("[%d] Program change (%d)\n",i,b1);
  1767.             trkloc[i] += 1;
  1768.             break;
  1769.           case 0xD0:                   // Channel Pressure
  1770.             //printf("[%d] Channel Pressure (%d,%d)\n",i,b1);
  1771.             trkloc[i] += 1;
  1772.             break;
  1773.           case 0xE0:                   // Pitch wheel change
  1774.             //printf("[%d] Pitch change (%d,%d)\n",i,b1,b2);
  1775.             trkloc[i] += 2;
  1776.             break;
  1777.           default:                     // Uh-OH
  1778.             //printf("MIDI ERROR (F0 midi command)\n");
  1779.             midi_on = FALSE;
  1780.             return;
  1781.         }
  1782.       }
  1783.                                          // read next time offset
  1784.       if(track_on[i]) {
  1785.         trkloc[i] += ReadVarLen(TD,&itmr);
  1786.         tmr[i] += itmr;
  1787.         //printf(" T: %ld\n",tmr[i]);
  1788.       }
  1789.     }
  1790.     tmr[i]-= 1.0 * midi_tempoadjust;                           // decrement timer
  1791.   }
  1792.  
  1793.                                         // Since there is a limited number
  1794.                                         // of FM voices, some notes do
  1795.                                         // not get voiced.  This next
  1796.                                         // section takes a list of
  1797.                                         // unallocated notes and tries
  1798.                                         // to find a spot for them.
  1799.   while(vhold) {
  1800.     vhold--;                            // go to next note
  1801.     for(i = 0; i < 9; i++) {            // loop through FM voices
  1802.       if(!v[i].active) {                // found empty one? set the note!
  1803.         v[i].owner_track = vh[vhold].owner_track;
  1804.         v[i].owner_channel = vh[vhold].owner_channel;
  1805.         v[i].note = vh[vhold].note;
  1806.         v[i].volume = vh[vhold].volume;
  1807.         v[i].active = TRUE;
  1808.         FM_SetNote(i,b1);
  1809.         FM_SetVol(i,music_volume);
  1810.         FM_KeyOn(i);
  1811.         break;
  1812.       }
  1813.     }
  1814.     if(i == 9) vhold = 0;               // List full? forget about other notes
  1815.   }
  1816.  
  1817.  
  1818. }
  1819.  
  1820. /**************************************************************************
  1821.   ReadMidi(char *filename, MIDI *mdata, char *errstring)
  1822.  
  1823.   DESCRIPTION: Reads a midi file and stores it to a MIDI data structure
  1824.  
  1825.   INPUTS:
  1826.  
  1827.     filename    Pointer to full midi filename
  1828.     midipoint    Indirect pointer to empty midi pointer
  1829.     errstring    Pointer to a pre-allocated string.
  1830.  
  1831.   Outputs:
  1832.     returns 0 if successful.
  1833.     On error, it returns a number and fills errstring with the
  1834.       error message.
  1835.  
  1836. **************************************************************************/
  1837. int ReadMidi(char *filename, MIDI **midipoint, char *errstring)
  1838. {
  1839.   int i;
  1840.   FILE *input;
  1841.   char sdata[256];
  1842.   long int lidata;
  1843.   int idata,lread;
  1844.   MIDI *mdata;
  1845.  
  1846.   input = fopen(filename,"rb");            // open a midi file
  1847.   if(!input) {
  1848.     sprintf(errstring,"cannot open %s",filename);
  1849.     return(1);
  1850.   }
  1851.                                            // Read the header
  1852.  
  1853.   fread(sdata,1,4,input);                  // midi id there?
  1854.   sdata[4] = 0;
  1855.   if(strcmp(sdata,"MThd")) {
  1856.     sprintf(errstring,"Not a  midi file.");
  1857.     fclose(input);
  1858.     return(2);
  1859.   }
  1860.   // printf("Chunk type: %s\n",sdata);
  1861.  
  1862.   lidata = ReadLong(input);                // length of remaining header chunk?
  1863.   // printf("Chunk length: %ld\n",lidata);
  1864.   if(lidata > 250) {
  1865.     sprintf(errstring,"Header chunk has a weird length");
  1866.     exit(0);
  1867.   }
  1868.  
  1869.   mdata = (MIDI *)malloc(sizeof(MIDI));    // make room for music!
  1870.   if(!mdata) {
  1871.     sprintf(errstring,"Out of memory.");
  1872.     fclose(input);
  1873.     return(3);
  1874.   }
  1875.   *midipoint = mdata;                       // Assign our pointer
  1876.  
  1877.   idata = ReadShort(input);                // Format
  1878.   //printf("Format: %d\n",idata);
  1879.   if(idata != 0 && idata != 1) {
  1880.     sprintf(errstring,"Unrecognized MIDI format");
  1881.     fclose(input);
  1882.     return(4);
  1883.   }
  1884.  
  1885.   mdata->format = idata;
  1886.  
  1887.   idata = ReadShort(input);                // number of tracks
  1888.   //printf("# of Tracks: %d\n",idata);
  1889.   if(idata < 1 || idata > 16) {
  1890.     sprintf(errstring,"Bad number of tracks [%d]",idata);
  1891.     fclose(input);
  1892.     return(5);
  1893.   }
  1894.   mdata->num_tracks = idata;
  1895.  
  1896.   idata = ReadShort(input);                // division number (tempo)
  1897.   //printf("1/4 note division: %d\n",idata);
  1898.   mdata->divisions = abs(idata);
  1899.  
  1900.                                            // Read individual track data
  1901.   for(i = 0; i < mdata->num_tracks; i++) {
  1902.     fread(sdata,1,4,input);                // midi track id there?
  1903.     sdata[4] = 0;
  1904.     if(strcmp(sdata,"MTrk")) {
  1905.       sprintf(errstring,"Error reading track #%d",i);
  1906.       fclose(input);
  1907.       return(6);
  1908.     }
  1909.     //printf("Chunk type: %s\n",sdata);
  1910.  
  1911.     lidata = ReadLong(input);              // length of remaining track chunk?
  1912.     //printf("Chunk length: %ld\n",lidata);
  1913.  
  1914.                                            // Allocate space for track
  1915.     mdata->track[i] = (BYTE *)malloc(lidata);
  1916.     if(!mdata->track[i]) {
  1917.       sprintf(errstring,"Out of memory.");
  1918.       fclose(input);
  1919.       return(3);
  1920.     }
  1921.                                            // read in entire track
  1922.     lread = fread(mdata->track[i],1,lidata,input);
  1923.     if(lread < lidata) {
  1924.       sprintf(errstring,"Premature end of midi file [track %d]",i);
  1925.       fclose(input);
  1926.       return(7);
  1927.     }
  1928.   }
  1929.  
  1930.   fclose(input);
  1931.   return 0;
  1932. }
  1933.  
  1934.  
  1935. /**************************************************************************
  1936.    int ReadVarLen(char *data,long int *value)
  1937.  
  1938.   DESCRIPTION:  Reads a variable length long interger from data string
  1939.  
  1940. **************************************************************************/
  1941. int ReadVarLen(BYTE *data,long int *value)
  1942. {
  1943.   int i=0;
  1944.   BYTE c;
  1945.  
  1946.   if ((*value = *(data + i)) & 0x80) {
  1947.     *value &= 0x7f;
  1948.     do {
  1949.       i++;
  1950.       *value = (*value << 7) + ((c = *(data +i)) & 0x7f);
  1951.     } while (c & 0x80);
  1952.   }
  1953.   return(i+1);                       // return number of bytes read
  1954. }
  1955.  
  1956.  
  1957. /**************************************************************************
  1958.   long int ReadShort(FILE *inflile)
  1959.  
  1960.   DESCRIPTION:  Reads a short interger from a file
  1961.  
  1962. **************************************************************************/
  1963. int ReadShort(FILE *infile)
  1964. {
  1965.   return (fgetc(infile) << 8) | fgetc(infile);
  1966. }
  1967.  
  1968. /**************************************************************************
  1969.   long int ReadLong(FILE *inflile)
  1970.  
  1971.   DESCRIPTION:  Reads a long interger from a file
  1972.  
  1973. **************************************************************************/
  1974. long int ReadLong(FILE *infile)
  1975. {
  1976.   int i;
  1977.   long int num = 0;
  1978.  
  1979.   num = (unsigned char)fgetc(infile);
  1980.  
  1981.   for(i = 0; i < 3; i++) {
  1982.     num = (num << 8) | (unsigned char)fgetc(infile);
  1983.   }
  1984.  
  1985.   return(num);
  1986. }
  1987.  
  1988.  
  1989. /**************************************************************************
  1990.   void playsound(SAMPLE *data,length)
  1991.  
  1992.   DESCRIPTION: Adds a sound to the play list.  If the playlist is full,
  1993.                all the sounds are scooted over and the new sound is  added
  1994.                as the last item;
  1995.  
  1996. **************************************************************************/
  1997. void playsound(SAMPLE *data,DWORD length)
  1998. {
  1999.   int i;
  2000.  
  2001.   if(sounds_in_queue >= MAXSOUNDS) {
  2002.     for(i= 0; i <sounds_in_queue; i++) {
  2003.       sounddata[i] = sounddata[i+1];
  2004.       soundpos[i] = soundpos[i+1];
  2005.     }
  2006.     sounds_in_queue--;
  2007.   }
  2008.  
  2009.  
  2010.   sounddata[sounds_in_queue] = data;
  2011.   soundpos[sounds_in_queue] = length-1;
  2012.  
  2013.   sounds_in_queue++;
  2014. }
  2015.  
  2016.  
  2017. /*********************************************************************
  2018.   SAMPLE *loadwave(char *wavefile,unsigned long int *length)
  2019.  
  2020.   DESCRIPTION:  Loads a wave files  (mono, 8bit)
  2021.  
  2022.   INTPUTS:
  2023.  
  2024.     wavefile  filename of wave file
  2025.     length    pointer to length interger
  2026.  
  2027.   RETURNS:
  2028.     pointer to data
  2029.  
  2030. **********************************************************************/
  2031. SAMPLE *loadwave(char *wavefile,unsigned long int *length)
  2032. {
  2033.   int i;
  2034.   SAMPLE  *data;
  2035.   BYTE dummydata[255];
  2036.   FILE *input;
  2037.   DWORD rlen,flen;
  2038.   WORD s_per_sec,b_per_sec,num_channels,tag;
  2039.   char riffid[5],waveid[5],fmtid[5],dataid[5];
  2040.  
  2041.   input = fopen(wavefile,"rb");
  2042.   if(!input) {                              // If unsuccesful...
  2043.     *length = 1;                             // set short length to prevent
  2044.                                             // mistakes later.
  2045.     return(NULL);                           // REturn a null pointer
  2046.   }
  2047.                                             // Get WAVE header data
  2048.  
  2049.   fread(riffid,1,4,input);                  // wave files staqrt with "Riff"
  2050.   riffid[4] = 0;
  2051.   fread(&rlen,1,4,input);                   // File size
  2052.   fread(waveid,1,4,input);                  // Wave id string  ("Wave")
  2053.   waveid[4] = 0;
  2054.   if(strcmp(waveid,"WAVE")) {               // is it a wave file?
  2055.     fclose(input);
  2056.     return(NULL);
  2057.   }
  2058.  
  2059.   fread(fmtid,1,4,input);                   // Format id string ("fmt ")
  2060.   fmtid[4] = 0;
  2061.   fread(&flen,1,4,input);                   // offset to data
  2062.   if(flen > 240) flen = 240;                // Just a precaution so that
  2063.                                             // We do not overload dummydata
  2064.  
  2065.   fread(&tag,1,2,input);                    // tag
  2066.   fread(&num_channels,1,2,input);           // number of channels
  2067.   fread(&s_per_sec,1,2,input);              // sample rate (hz)
  2068.   fread(&b_per_sec,1,2,input);              // bytes per seconf rate
  2069.   fread(dummydata,1,flen-8,input);          // Skip ahead
  2070.   fread(dataid,1,4,input);                  // Dataid string
  2071.   dataid[4] = 0;
  2072.   fread(length,1,4,input);                  // length of data
  2073.  
  2074.   data = (SAMPLE *)farmalloc(*length+1);  // allocate memory for data
  2075.   if(!data) {                                // oops.  Not enough mem!
  2076.     fclose(input);
  2077.     return(NULL);
  2078.   }
  2079.  
  2080.   fread(data,1,*length,input);              // read the data
  2081.  
  2082.   for(i = 0; i < *length; i++) {            // convert to signed format
  2083.     *(data + i) = ((BYTE)*(data + i))-128;
  2084.   }
  2085.  
  2086.   fclose(input);                            // Wrap it up
  2087.   return(data);
  2088. }
  2089.  
  2090.  
  2091. /**************************************************************************
  2092.   void load_instruments(char *filename,BYTE inst[128][11])
  2093.  
  2094.   DESCRIPTION:  Loads instrument defs from a file (128)
  2095.  
  2096.     File format: 11 hex values followed by a name.  eg:
  2097.  
  2098.       30 33 40 00 E1 E2 87 63 06 01 00 "Electric Piano 2"
  2099.       33 34 00 00 92 C3 C3 B3 02 01 00 "Harpsichord"
  2100.       32 32 00 00 92 C3 C3 B3 02 01 00 "Clavichord"
  2101.       .
  2102.       .
  2103.       .
  2104.  
  2105.     (The name is not loaded.)
  2106.  
  2107.     The hex values are dumped into an 2-D array.  The file can have
  2108.     more or less than 128 defs without harm to this function.
  2109.  
  2110. **************************************************************************/
  2111. int load_instruments(char *filename,BYTE inst[128][11])
  2112. {
  2113.   FILE *input;
  2114.   int i=0,j;
  2115.   char string[255];
  2116.  
  2117.   input = fopen(filename,"r");     // open the file
  2118.   if(!input) return(0);
  2119.                                    // read  it's contents
  2120.   while(fgets(string,255,input) && i < 128) {
  2121.     for(j = 0; j < 11; j++) sscanf(string+j*3,"%X ",&inst[i][j]);
  2122.     i++;
  2123.   }
  2124.                                    // clean up and go home
  2125.   fclose(input);
  2126.   return(i);
  2127. }
  2128.  
  2129.  
  2130.  
  2131. /**************************************************************************
  2132.   void freemidi(MIDI *m)
  2133.  
  2134.   DESCRIPTION: Frees the data allocated for a MIDI structure
  2135.  
  2136. **************************************************************************/
  2137. void freemidi(MIDI *m)
  2138. {
  2139.   int i;
  2140.  
  2141.   for(i = 0; i < m->num_tracks; i++) free(m->track[i]);
  2142.   free(m);
  2143. }
  2144.